當etcd收到Client發出的操作請求時, 會呼叫AppendEntries把操作命令當成一個指令的Entry寫在log裡, 並標上Index.
然後再把log當成message傳送給Follower.
Follower收到log後也是會Append entry, 並且返回對應的回應訊息給Leader.
Leader一樣收到半數以上的回應後, 就把Entry給commit成committed
, 並返回操作結果給Client, 然後也把commit給包成raftlog給Append Entry.
等到下一次heartbeat發送時, 就把Entries也帶過去通知Follower們執行commit.
這時候集群的狀態就完成一致了, 這個過程就是日誌複製Log Replication
當然以上是Raft的日誌複製.
其實也很像二階段提交(2PC),
第一階段做把日誌對Folloer做日誌複製, 等過半都複製完成時, 做本地commit, 就回應給Client.
第二階段是異步的, Leader就週期性地把提交資訊透過heartbeat提交給Follower, 所以Follower們也會完成commit.
etcd的話, 內部核心稍微複雜點
主要定義了etcd對client的核心接口.
還有跟內部其他模組的設定與溝通.
其中id
該節點的IDappliedINdex
就是用來紀錄目前這server節點已經Apply的Entry紀錄的最大索引值.committedIndex
就是紀錄已經提交成功的Entry紀錄的索引值.inflightSnapshots
已經發送出去但還沒收到ack的快照數量.leadElecttedTime
紀錄該節點最近一次當上Leader狀態的時間戳記.cluster
目前cluster中所有節點的資訊.snapshotter
讀寫快照檔案snapCount
一個門閥值, 當目前的entry數量距離上一次快照的entry數量, 超過這閥值時, 就會觸發快照.compactor
用來控制定期壓縮的頻率
非常多配置QQ
實現了Raft演算法的功能, 就這三篇一直介紹的內容.
主要用來儲存Raft節點臨時的資料與數據, 像是entry, snapshot, 節點狀態...etc, 還沒提交之前暫存用.
也用來存放之前提及的KeyIndex.
就在執行操作命令前先寫入一條日誌(很像MySQL的redo log).
這日誌會以xxxxxxxxx.wal的檔名存在於節點的文件上.
每個WAL檔案大小為64MB, 超過就會生成新的檔案, 該檔案用flock文件鎖做鎖定, 所以同時間也只有一個執行緒能操作.
儲存和讀取快照用.
檔名是xxxx.snap.
如果節點當機了, 要從WAL日誌文件來復原, 很耗時.
從快照來加載, 在從快照之後的相對位置來開始讀取WAL日誌文件, 就快非常多了.
藉由EtcdSever:triggerSnapshot來決定是否觸發快照行為, 裡面會判斷SnapshotCount.
EtcdSErver:snapshot執行完快照後, 會把被載入快照的WAL檔都刪除(Storage:Release).
etcd V3的backend store預設使用的就是BoltDB.
這部份在之前介紹過了.
參考:
In Search of an Understandable Consensus Algorithm這份論文對Raft和日誌複製有詳細的說明.
Raft演算法動畫
接著數篇就介紹些Client API跟做點範例.